import { Form, FormItemProps, InputProps } from 'antd';
import React, { Context, ReactElement, useContext, useMemo } from 'react';
import { Utils } from './utils.ts';
import { FeatureFormContext } from '../feature-form/context.ts';
import { ApiPropertyDecorate } from '@quick-toolkit/http';
import { FeatureConfigContext } from '../feature-config-provider';
import I18n from '@quick-toolkit/i18n';
import type { LocaleLanguageKey } from '@quick-toolkit/http/dist/types/constants/locale-language';
import { ConfigContext } from 'antd/es/config-provider';

export interface FeatureFormItemProps<T extends object>
  extends Omit<FormItemProps, 'name'> {
  name: keyof T;
  index?: number;
}

export interface FeatureFormItemNoNameProps
  extends Omit<FormItemProps, 'name'> {
  name?: never;
  index?: never;
}

export function FeatureFormItem<T extends object>(
  props: FeatureFormItemProps<T> | FeatureFormItemNoNameProps,
) {
  const {
    index,
    name,
    label,
    hidden,
    children,
    shouldUpdate,
    rules = [],
    ...rest
  } = props;
  const config = useContext(FeatureConfigContext);
  const i18n = useContext(config.contexts.i18n as Context<I18n<object>>);
  const mirrorMapper = useContext(FeatureFormContext);
  const antConfig = useContext(ConfigContext);

  const mixinProps = useMemo(() => {
    if (shouldUpdate) {
      return { children, shouldUpdate };
    }
    const namePath = Utils.createNamePath(name as string, index);
    const result: FormItemProps = {
      name: namePath,
      rules: Array.from(rules),
      hidden,
      label,
      children: children,
    };

    // If the name exists and the element is not hidden, generate labels, placeholders, and rules
    if (name && !hidden) {
      const mirror = mirrorMapper.get(name);
      mirror?.getAllDecorates(ApiPropertyDecorate).forEach((decorate) => {
        const hasRequired = result?.rules?.some(
          (rule) => typeof rule !== 'function' && rule.required !== undefined,
        );
        const language = i18n.locale() as LocaleLanguageKey;
        // If not label
        if (label === undefined && language) {
          const locale = decorate?.metadata?.locales?.[language];
          if (locale) {
            result.label = locale;
          } else {
            result.label = decorate?.metadata?.description;
          }
        }

        if (decorate?.metadata?.required !== undefined) {
          if (decorate?.metadata?.required === true) {
            if (!hasRequired) {
              result?.rules?.push({
                required: true,
              });
            }
          } else {
            result.rules = result?.rules?.filter(
              (o) => !(o as { required?: boolean }).required,
            );
          }
        }

        if (typeof result.label === 'string') {
          const only = React.Children.only(
            children,
          ) as ReactElement<InputProps>;
          const requiredText =
            antConfig.locale?.Form?.defaultValidateMessages.required;
          if (typeof requiredText === 'string') {
            result.children = React.cloneElement(only, {
              placeholder:
                only.props?.placeholder ||
                requiredText.replace('${label}', result.label),
            });
          } else {
            result.children = React.cloneElement(only, {
              placeholder: only.props?.placeholder || result.label,
            });
          }
        }
      });
    }

    return result;
  }, [
    antConfig.locale?.Form?.defaultValidateMessages.required,
    children,
    hidden,
    i18n,
    index,
    label,
    mirrorMapper,
    name,
    rules,
    shouldUpdate,
  ]);

  return <Form.Item {...mixinProps} {...rest} />;
}
